package com.cd826dong.clouddemo.service;

import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ZHOUTIEQIANG053
 *上面的代码以下几点需要说明。
·对于请求合并的处理，需要实现上继承HystrixCollapser基类；
·还需要实现一个批量请求的BatchCommand，该Command负责调用用户服务的批量查询方法；
·然后再实现mapResponseToRequests（）方法，将批量返回的结果映射到每个请求中。

Hystrix支持将多个请求自动合并为一个请求，通过合并可以减少
HystrixCommand并发执行所需的线程和网络连接数量，极大地节省了
开销，提高了系统效率。请求合并是由Hystrix自动合并进行的，并不
需要在开发时进行代码介入（注意，这里只是说合并请求不需要代码
介入，但对于批量请求的处理，还是需要写一些代码的）。需要注意
的是，多个请求能自动合并的前提是请求之间要足够“近”，即执行的
间隔时长要足够小（默认为10ms，可通过
hystrix.collapser.default.timerDelayInMilliseconds进行设置），即执行间
隔超过10ms的请求不会合并执行。

请求都是调用的  /user/{names} 方法  com.cd826dong.clouddemo.provider.api.UserEndPoint
 */
public class UserCommandCollapserService extends
		HystrixCollapser<List<String>, String, String> {

	private UserService userService;

	private String name;

	public UserCommandCollapserService(UserService userService, String name) {
		this.userService = userService;
		this.name = name;
	}

	@Override
	public String getRequestArgument() {
		return this.name;
	}

	@Override
	protected HystrixCommand<List<String>> createCommand(
			Collection<CollapsedRequest<String, String>> collapsedRequests) {
		List<String> names = new ArrayList<>(collapsedRequests.size());
		names.addAll(collapsedRequests.stream()
				.map(CollapsedRequest::getArgument)
				.collect(Collectors.toList()));
		return new BacthCommand(userService, names);
	}

	@Override
	protected void mapResponseToRequests(List<String> batchResponse,
			Collection<CollapsedRequest<String, String>> collapsedRequests) {
		int count = 0;
		for (CollapsedRequest<String, String> request : collapsedRequests) {
			request.setResponse(batchResponse.get(count++));
		}
	}

	private static final class BacthCommand extends
			HystrixCommand<List<String>> {
		private UserService userService;
		private List<String> names;

		private BacthCommand(UserService userService, List<String> names) {
			super(
					Setter.withGroupKey(
							HystrixCommandGroupKey.Factory.asKey("UserCommand"))
							.andCommandKey(
									HystrixCommandKey.Factory
											.asKey("GetUserId")));
			this.userService = userService;
			this.names = names;
		}

		@Override
		protected List<String> run() throws Exception {
			return userService.names(StringUtils.join(names, ","));
		}
	}
}
